/* ===================

AX2E (AXESCON XACML 2.0 Engine) is the Java authorization engine, which implements OASIS XACML 2.0 standard.
Copyright (C) 2007 AXESCON LLC

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA


Contact: AXESCON LLC - info{at}axescon.com

 =================== */
package axescon.xacml.samples.rbac_2_0;

import axescon.xacml.api.*;
import axescon.xacml.api.alg.PolicyCombAlg;
import axescon.xacml.api.alg.PolicyCombAlgFactory;
import axescon.xacml.engine.alg.BasePolicyCombAlgFactory;
import axescon.xacml.model.ctx.XacmlCtx;
import axescon.xacml.model.policy.Target;
import axescon.xacml.model.policy.PolicyProxy;
import axescon.xacml.model.policy.impl.PolicySetImpl;
import axescon.xacml.model.policy.impl.TargetImpl;

import java.io.ByteArrayOutputStream;
import java.util.List;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * @author argyn
 *         Date: Jan 29, 2006
 *         Responsibilities: this is decorator policy store, it uses original policy store
 *         to lookup policies by taget matching. if more than one policy is found, then it wraps
 *         all these policies into one policy set with permit overrides alg.
 *         it's usefull for RBAC policies, where subjects can have more ythan one role, i.e. RPS.
 */
public class MultiPolicyStoreWrapper implements PolicyStore {
    static Logger log = Logger.getLogger(MultiPolicyStoreWrapper.class.getName());

    protected PolicyStore ps;

    public MultiPolicyStoreWrapper() {
    }

    public MultiPolicyStoreWrapper(PolicyStore ps) {
        this.ps = ps;
    }

    public PolicyStore getPs() {
        return ps;
    }

    public void setPs(PolicyStore ps) {
        this.ps = ps;
    }

    public PolicyFactory getPolicyFactory() {
        return ps.getPolicyFactory();
    }

    public void setPolicyFactory(PolicyFactory policyFactory) {
        ps.setPolicyFactory(policyFactory);
    }

    public void validate(PolicyEvaluator pe) throws XacmlException {
        ps.validate(pe);
    }

    /**
     * this method wraps multiple policy sets into one policy set
     *
     * @param req XACML Request
     * @param ch  context handler
     * @param tm  target matcher
     * @return List<PolicyObject> , this list will always have one element or empty
     * @throws XacmlException
     */
    public List find(XacmlCtx req, CtxHandler ch, TargetMatcher tm) throws XacmlException {
        List ret = ps.find(req, ch, tm);
        if (ret != null && ret.size() > 1) {
            log.fine("found "+ret.size()+" policies matching request, they are being wrapped into one set.");

            // define the identifier for the policy
            String policyId = "Wrapped:PolicySet";

            // get the combining algorithm for the policy
            String combiningAlgId = PolicyCombAlg.PERMIT_OVERRIDES;

            // add a description for the policy
            String description =
                    "This policy set wraps all applicable policies.";

            Target target = new TargetImpl();

            // create the policy
            PolicySetImpl retPs = new PolicySetImpl();
            retPs.setId(policyId);
            retPs.setPolicyCombiningAlgId(combiningAlgId);
            retPs.setDescription(description);
            retPs.setTarget(target);
            retPs.setPolicyProxyArray((PolicyProxy[])ret.toArray(new PolicyProxy[ret.size()]));

            // finally, encode the policy and print it to standard out
            ret = new ArrayList(1);
            ret.add(retPs);
        }

        return ret;
    }


}
